<?php
// +-----------------------+
// | 注释不留名，代码随便用 |
// +-----------------------+


namespace addons\library;


use addons\library\plugs\Part;
use addons\library\plugs\Module;
use library\tools\Http;

abstract class Plugs
{
    protected $name;
    protected $local;

    public function __construct($name)
    {
        $this->name = $name;
        $this->setLocal();
    }


    /**
     * @return String
     */
    abstract public function setLocal($local = '');

    public function getLocal()
    {
        return $this->local;
    }

    /**
     * 插件启动类
     * @return mixed
     */
    abstract public function getBootstrapClass();

    /**
     * 安装
     * @param $name
     * @param $file
     * @return mixed
     */
    public function install($file, $param = [])
    {
        $this->downloadFile($file, $param);
        $this->deployAssets(ADDON_PATH . $this->name . DIRECTORY_SEPARATOR . 'config.php');
        $bootstrapClasses = $this->getBootstrapClass();
        if (class_exists($bootstrapClasses)) {
            (new $bootstrapClasses)->install();
        }
    }


    /**
     * 卸载
     * @param $name
     * @return mixed
     */
    public function uninstall()
    {
        $bootstrapClasses = $this->getBootstrapClass();
        if (class_exists($bootstrapClasses)) {
            (new $bootstrapClasses)->uninstall();
        }
        $this->removeSource();
        $this->deployAssets();
    }

    /**
     * 下载文件
     * @param $remote 远程url
     */
    protected function downloadFile($remote, $param = [])
    {
        $buffer = Http::get($remote, $param);
        $finfo = new \finfo(FILEINFO_MIME_TYPE);
        $mime = $finfo->buffer($buffer);
        if ('application/zip' !== $mime) {
            throw new AddonsException('远程文件不存在！');
        }
        $tarter_file = env('app_path') . time() . '.zip';
        file_put_contents($tarter_file, $buffer);
        $zip = new \ZipArchive;
        if ($zip->open($tarter_file) !== true) {
            throw new AddonsException('解压zip文件失败！');
        }
        $zip->extractTo($this->local);
        if (is_dir($this->local . $this->name)) {
            @delDir($this->local . $this->name);
        }
        $zipdir = $zip->getNameIndex(0);
        $zip->close();
        unlink($tarter_file);
        $this->rename($this->local . $zipdir, $this->local . $this->name);
    }

    /**
     * 部分环境直接使用 rename会报 php rename() Access is denied. (code: 5)
     * @param $oldfile
     * @param $newfile
     * @return bool
     */
    public function rename($oldfile, $newfile)
    {
        if (!@rename($oldfile, $newfile)) {
            if (copydirs($oldfile, $newfile)) {
                delDir($oldfile);
                return true;
            }
            return true;
        }
    }


    /**
     * 配置相关资源
     */
    public function deployAssets($configFile = '')
    {
        $name = $this->name;
        $assets = ASSETS_PATH . $name . DIRECTORY_SEPARATOR;
        $source = $this->local . $name . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR;
        $config = config('addons.');
        $js = [];
        $css = [];
        if (is_dir($source)) {
            copydirs($source, $assets);
            if (is_file($assets . 'bootstrap.js')) {
                $config['pre_load']['js'][$name] = '/addons/' . $name . '/bootstrap.js';
            }
            if (is_file($assets . 'bootstrap.css')) {
                $config['pre_load']['css'][$name] = '/addons/' . $name . '/bootstrap.css';
            }
        } else {
            //文件被移除
            unset($config['pre_load']['js'][$name]);
            unset($config['pre_load']['css'][$name]);
            unset($config[$name]);
        }
        if (is_file($configFile)) {
            $config[$name] = include($configFile);
        }
        file_put_contents(env('root_path') . 'config/addons.php', "<?php\n\n" . "return " . var_export($config, TRUE) . ";\n");

    }

    protected function removeSource()
    {
        delDir($this->local . $this->name . DIRECTORY_SEPARATOR);
        $assets = ASSETS_PATH . $this->name . DIRECTORY_SEPARATOR;
        if (is_dir($assets)) {
            delDir($assets);
        }
    }

    /**
     * 工厂方法
     * @param $type
     * @return Plugs
     */
    public static function factory($type, $module)
    {
        switch ($type) {
            case 1:
                $addons = new Module($module);
                break;
            case 2:
                $addons = new Part($module);
                break;
        }
        return $addons;
    }
}